es7 https://github.com/rccoder/blog/issues/23

装饰器的原理

语法糖,实则调用 Object.defineProperty,可以添加、修改对象属性

JS 装饰器

Decorator 其实是语法糖,实则调用 Object.defineProperty,可以添加、修改对象属性。Decorator 是 ES7 的一个新语法,目前仍处于第 2 阶段提案中,正如其“装饰器”的叫法所表达的,他通过添加@方法名可以对一些对象进行装饰包装然后返回一个被包装过的对象,可以装饰的对象包括:类,属性,方法等。

在使用它之前需要引入 babel 模块 transform-decorators-legacy 编译成 ES5 或 ES6。

1. 类的装饰

当装饰的对象是类时,我们操作的就是这个类本身,即装饰器函数的第一个参数,就是所要装饰的目标类。

@decorator
class A {}

// 等同于
class A {}
A = decorator(A) || A;
123456;

示例:添加一个日志装饰器

@log
class MyClass {}

function log(target) {
  // 这个 target 在这里就是 MyClass 这个类
  target.prototype.logger = () => `${target.name} 被调用`;
}

const test = new MyClass();
test.logger(); // MyClass 被调用

由于装饰器是表达式,我们也可以在装饰器后面再添加个参数:

@log("hi")
class MyClass {}

function log(text) {
  return function (target) {
    target.prototype.logger = () => `${text}${target.name} 被调用`;
  };
}

const test = new MyClass();
test.logger(); // hello,MyClass 被调用
1234567891011;

2. 属性或方法的装饰

对于类属性或方法的装饰本质是操作其描述符,可以把此时的装饰器理解成是 Object.defineProperty(obj, prop, descriptor)的语法糖。

class C {
  @readonly(false)
  method() {
    console.log("cat");
  }
}

function readonly(value) {
  return function (target, key, descriptor) {
    /**
     * 此处 target 为 C.prototype;
     * key 为 method;
     * 原 descriptor 为:{ value: f, enumarable: false, writable: true, configurable: true }
     */
    descriptor.writable = value;
    return descriptor;
  };
}

const c = new C();
c.method = () => console.log("dog");

c.method(); // cat

请介绍一下装饰者模式,并实现

装饰器(Decorator)用来增强 JavaScript 类(class)的功能,许多面向对象的语言都有这种语法,如 Java 的注解(Annotation)。

饰器是一种函数,写成@ + 函数名,可以用来装饰四种类型的值。

  1. 类。 操作类本身。
  2. 类的属性。 通过 Object.defineProperty() 操作类的属性。
  3. 类的方法
  4. 存值器(setter)和取值器(getter)
class C {
  @trace
  toString() {
    return "C";
  }
}

// 相当于
C.prototype.toString = trace(C.prototype.toString);

装饰器

是如何实现的?

https://segmentfault.com/p/1210000009968000/read

为什么装饰器不能用于函数

装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。

总之,由于存在函数提升,使得装饰器不能用于函数。类是不会提升的,所以就没有这方面的问题。

另一方面,如果一定要装饰函数,可以采用高阶函数的形式直接执行。

Last Updated:
Contributors: yiliang114